package cn.e4j.modular.system.service.impl;

import cn.e4j.core.dto.impl.Dto;
import cn.e4j.core.quartz.QuartzUtil;
import cn.e4j.core.shiro.ShiroKit;
import cn.e4j.core.shiro.ShiroUser;
import cn.e4j.core.util.AppCxt;
import cn.e4j.core.util.DateUtils;
import cn.e4j.core.util.ToolUtil;
import cn.e4j.modular.system.entity.SysTask;
import cn.e4j.modular.system.mapper.SysTaskMapper;
import cn.e4j.modular.system.service.SysTaskService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.*;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * <p>
 * 定时任务服务类
 * </p>
 *
 * @author yuan_rz
 * @since 2019-03-11
 */
@Service("sysTaskService")
public class SysTaskServiceImpl extends ServiceImpl<SysTaskMapper, SysTask> implements SysTaskService {
    private SchedulerFactory schedulerFactory = new StdSchedulerFactory();
    private Scheduler scheduler = null;

    @Transactional(readOnly = true)
    public List<SysTask> getListData(Page<Object> page, Dto dto) {
        List<SysTask> listData = this.baseMapper.getListData(page, dto);
        return listData;
    }

    @Transactional
    public void addData(SysTask sysTask) {
        //新增
        sysTask.insert();
    }

    @Transactional
    public void editData(SysTask sysTask) {
        sysTask.updateById();
    }

    @Transactional
    public void deleteData(SysTask sysTask) {
        delete(sysTask);
    }

    @Transactional
    public void deleteDataBatch(List<SysTask> sysTaskList) {
        for (int i = 0; i < sysTaskList.size(); i++) {
            delete(sysTaskList.get(i));
        }
    }

    /**
     * 系统初始化启用定时任务
     *
     * @param dto
     * @return
     */
    @Transactional(readOnly = true)
    public List<SysTask> initTask(Dto dto) throws SchedulerException, ParseException, ClassNotFoundException {
        List<SysTask> listData = this.baseMapper.getListData(dto);
//        scheduler = schedulerFactory.getScheduler();
//        if(!scheduler.isStarted()){
//            scheduler.start();
//        }
//        for (SysTask sysTask :listData) {

//            //唯一ID
//            String run_id = sysTask.getID();
//            //JobDetail
//            JobDetail job = getTaskJob(sysTask, run_id,null);
//            CronTrigger trigger = newTrigger().withIdentity(run_id, run_id).withSchedule(cronSchedule(sysTask.getTASK_RULE())).build();
//
//            scheduler.scheduleJob(job, trigger);
//        }
        return listData;
    }

    @Transactional
    public void runTask(SysTask sysTask) throws SchedulerException, ParseException, ClassNotFoundException {
//        scheduler = schedulerFactory.getScheduler();
//        if (!scheduler.isStarted()) {
//            scheduler.start();
//        }
//
//        //唯一ID
//        String run_id = sysTask.getID();
//        //JobDetail
//        JobDetail job = getTaskJob(sysTask, run_id, null);
//        CronTrigger trigger = newTrigger().withIdentity(run_id, run_id).withSchedule(cronSchedule(sysTask.getTASK_RULE())).build();
//
//        if (scheduler.checkExists(job.getKey())) { //存在暂停的定时任务，就删除
//            JobKey jobKey = JobKey.jobKey(run_id, run_id);
//            scheduler.deleteJob(jobKey);
//        }
//
//        scheduler.scheduleJob(job, trigger);

        //归零任务连续错误次数
        sysTask.setTASK004(0);
        //修改状态为启用
        sysTask.setTASK_STATUS("1");

        sysTask.updateById();
    }

    @Transactional
    public void stopTask(SysTask sysTask) throws SchedulerException {
//        scheduler = schedulerFactory.getScheduler();
//
//        JobKey jobKey = JobKey.jobKey(sysTask.getID(), sysTask.getID());
//        scheduler.pauseJob(jobKey);

        sysTask.setTASK_STATUS("0");
        sysTask.updateById();
    }

    public void runTaskOnce(SysTask sysTask, Dto inDto) throws SchedulerException, ParseException, ClassNotFoundException {
        scheduler = schedulerFactory.getScheduler();
        if (!scheduler.isStarted()) {
            scheduler.start();
        }
        //唯一ID
        String run_id = AppCxt.timeId();
        //JobDetail
        JobDetail job = getTaskJob(sysTask, run_id, inDto);
        SimpleTrigger trigger = newTrigger().withIdentity(run_id, run_id)
                .startAt(new Date()).withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(3)
                        .withRepeatCount(0))//重复执行的次数，因为加入任务的时候马上执行了，所以不需要重复，否则会多一次。
                .build();
        scheduler.scheduleJob(job, trigger);
    }

    public List<String> lastFiveTimes(String cron) throws ParseException {
        List<String> list = new ArrayList<>();
        CronExpression exp = new CronExpression(cron);
        Date date = new Date();
        for (int i = 0; i < 5; i++) {
            date = exp.getNextValidTimeAfter(date);
            if (date == null) {
                break;
            }
            list.add(DateUtils.formatDateTime(date));
        }
        return list;
    }

    /**
     * 获取TaskJob
     *
     * @param sysTask 任务配置
     * @param run_id  运行ID
     * @param inDto   为了适配不同类型的定时任务而添加的参数
     *                1.当为同步任务时，应包含loadid;可包含trandate,格式为yyyy-MM-dd hh:mm:ss,如果不包含则通过loadid到数据库里去取trandate
     * @return
     * @throws SchedulerException
     * @throws ParseException
     * @throws ClassNotFoundException
     */
    private JobDetail getTaskJob(SysTask sysTask, String run_id, Dto inDto) throws SchedulerException, ParseException, ClassNotFoundException {
        ShiroUser shiroUser = ShiroKit.getUser();
        scheduler = schedulerFactory.getScheduler();
        //验证表达式
        lastFiveTimes(sysTask.getTASK_RULE());
        //获取定时任务全路径
        Class task = Class.forName(sysTask.getTASK_CLASS());
        //JobDetail
        JobDetail job = newJob(task).withIdentity(run_id, run_id).build();
        //传递参数
        Map<String, String> params = new HashMap<>();
        if (shiroUser != null) {
            params.put("user", shiroUser.getID());
            params.put("ent", shiroUser.getDBC());
            params.put("site", shiroUser.getSITE());
        }
        params.put("taskid", sysTask.getID());
        job.getJobDataMap().put("data", params);
        //如果任务为同步数据任务
        if ("1".equals(sysTask.getTASK_GROUP())) {
            //loadid
            params.put("loadid", sysTask.getTASK001());
            //trandate
            if (inDto != null && ToolUtil.isNotEmpty(inDto.getString("trandate"))) {
                params.put("trandate", DateUtils.formatDateTime(DateUtils.parseDate(inDto.getString("trandate"))));
            }
        }
        return job;
    }

    private void delete(SysTask sysTask) {
        sysTask.deleteById();
    }


}
